package com.github.linkoog.model_designer.ide.editer;

import com.github.linkoog.model_designer.common.JCheckBoxTableCellEditor;
import com.github.linkoog.model_designer.common.JCheckBoxTableCellRenderer;
import com.github.linkoog.model_designer.common.JComboEnumTableCellEditor;
import com.github.linkoog.model_designer.ide.editer.common.Column;
import com.github.linkoog.model_designer.ide.editer.common.ColumnVo;
import com.github.linkoog.model_designer.ide.editer.common.DataType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.ui.table.JBTable;
import com.linkoog.devtools.utils.StringUtils;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class ColumnsJTableModel extends AbstractTableModel implements Serializable {

    private static final Logger logger = Logger.getInstance(ColumnsJTableModel.class);

    private final List<String> columnList = Arrays.asList("#", "列名", "数据类型", "长度", "小数点", "Not Null","主键","默认值","注释","Mock规则");

    //dialectType
    private final List<String> columnFieldList = Arrays.asList("#", "name", "dataType", "length", "radix", "notNull","primaryKey","defaultValue","comment","mockRule");

    private final List<Column> dataList = new ArrayList<>();

    private List<Column> tempDataList;

    private DataChangedListener dataChangedListener;


    public ColumnsJTableModel(){
    }

    public ColumnsJTableModel(Collection<Column> newRowList) {
        addRow(newRowList);
    }

    public void initTableColumn(JBTable jbTable){
        DefaultTableCellRenderer tableCellRenderer = new DefaultTableCellRenderer();
        tableCellRenderer.setHorizontalAlignment(SwingConstants.CENTER);
        tableCellRenderer.setBackground(Color.LIGHT_GRAY);


        int rownoIndex = 0;
        TableColumn rownoColumn = jbTable.getColumn(columnList.get(rownoIndex));
        rownoColumn.setMinWidth(46);
        rownoColumn.setMaxWidth(46);
        rownoColumn.setPreferredWidth(46);
        rownoColumn.setCellRenderer(new DefaultTableCellRenderer(){
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                DefaultTableCellRenderer component = (DefaultTableCellRenderer)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                component.setHorizontalAlignment(SwingConstants.CENTER);
                component.setText("" + (row + 1));
                return component;
            }
        });


        int tableNameIndex = 1;
        TableColumn tableNameColumn = jbTable.getColumn(columnList.get(tableNameIndex));
        tableNameColumn.setMinWidth(115);
        tableNameColumn.setMaxWidth(115);
        tableNameColumn.setPreferredWidth(115);
        tableNameColumn.setCellRenderer(new DefaultTableCellRenderer(){
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                DefaultTableCellRenderer component = (DefaultTableCellRenderer)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                component.setHorizontalAlignment(SwingConstants.LEFT);
                return component;
            }
        });

        //数据类型
        int dataTypeIndex = 2;
        TableColumn dataTypeColumn = jbTable.getColumn(columnList.get(dataTypeIndex));
        dataTypeColumn.setMinWidth(95);
        dataTypeColumn.setMaxWidth(95);
        dataTypeColumn.setPreferredWidth(95);
        //dataTypeColumn.setCellRenderer(tableCellRenderer);
        dataTypeColumn.setCellEditor(new JComboEnumTableCellEditor(DataType.class, false));


        //长度
        int lengthIndex = 3;
        TableColumn lengthColumn = jbTable.getColumn(columnList.get(lengthIndex));
        lengthColumn.setMinWidth(48);
        lengthColumn.setMaxWidth(48);
        lengthColumn.setPreferredWidth(48);
        lengthColumn.setCellRenderer(tableCellRenderer);


        //小数点
        int radixIndex = 4;
        TableColumn radixColumn = jbTable.getColumn(columnList.get(radixIndex));
        radixColumn.setMinWidth(48);
        radixColumn.setMaxWidth(48);
        radixColumn.setPreferredWidth(48);
        radixColumn.setCellRenderer(tableCellRenderer);

        //Not Null
        int notNullIndex = 5;
        TableColumn notNullColumn = jbTable.getColumn(columnList.get(notNullIndex));
        notNullColumn.setMinWidth(60);
        notNullColumn.setMaxWidth(60);
        notNullColumn.setPreferredWidth(60);
        notNullColumn.setCellRenderer(new JCheckBoxTableCellRenderer());
        notNullColumn.setCellEditor(new JCheckBoxTableCellEditor());

        //主键
        int primaryKeyIndex = 6;
        TableColumn primaryKeyColumn = jbTable.getColumn(columnList.get(primaryKeyIndex));
        primaryKeyColumn.setMinWidth(60);
        primaryKeyColumn.setMaxWidth(60);
        primaryKeyColumn.setPreferredWidth(60);
        primaryKeyColumn.setCellRenderer(new JCheckBoxTableCellRenderer());
        primaryKeyColumn.setCellEditor(new JCheckBoxTableCellEditor());

        //默认值
        int defaultValueIndex = 7;
        TableColumn defaultValueColumn = jbTable.getColumn(columnList.get(defaultValueIndex));
        defaultValueColumn.setMinWidth(115);
        defaultValueColumn.setMaxWidth(115);
        defaultValueColumn.setPreferredWidth(115);
        defaultValueColumn.setCellRenderer(tableCellRenderer);

        //注释
        int tableCommentIndex = 8;
        TableColumn tableCommentColumn = jbTable.getColumn(columnList.get(tableCommentIndex));

    }


    @Override
    public int getRowCount() {
        return dataList.size();
    }

    @Override
    public int getColumnCount() {
        return columnList.size();
    }

    @Override
    public String getColumnName(int columnIndex) {
        /*if (columnIndex == 4){
            return "";
        }*/
        return columnList.get(columnIndex);
    }

    public String getColumnField(int columnIndex){
        return columnFieldList.get(columnIndex);
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Column column = dataList.get(rowIndex);
        ColumnVo columnVo = column.getColumnVo();
        switch (columnIndex){
            case 1: return column.getName();
            case 2: return columnVo.getDataType().getValue();
            case 3: return columnVo.getLength();
            case 4: return columnVo.getRadix();
            case 5: return columnVo.getNotNull();
            case 6: return columnVo.getPrimaryKey();
            case 7: return columnVo.getDefaultValue();
            case 8: return columnVo.getComment();
            case 9: return columnVo.getMockRule();
        }
        return null;
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        if (columnIndex == 0){
            return false;
        }

        Column column = dataList.get(rowIndex);
        if (!column.isColumnVo()){
            return columnIndex == 1;
        }

        switch (columnIndex){
            case 1:  return true;
        }
        return true;
    }

    @Override
    public Class getColumnClass(int columnIndex)	{
        Object value = getValueAt(1, columnIndex);
        if(value != null){
            return value.getClass();
        } else {
            return super.getClass();
        }
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        if (columnIndex == 0){
            return;
        }

        Column column = dataList.get(rowIndex);
        String field = getColumnField(columnIndex);
        if (columnIndex == 1){
            String newVal = (String) aValue;
            if (column.getName().equals(newVal) || StringUtils.isBlank(newVal)){
                return;
            }

            if (dataChangedListener != null){
                dataChangedListener.dataChanged(rowIndex, columnIndex, column, field, newVal);
            }
            column.setName(newVal);
            return;
        }

        if (!column.isColumnVo()){
            return;
        }

        String newVal = parseData(aValue);
        ColumnVo columnVo = column.getColumnVo();
        if (columnVo.getField(field).equals(newVal)){
            return;
        }

        if (dataChangedListener != null){
            dataChangedListener.dataChanged(rowIndex, columnIndex, column, field, newVal);
        }
        columnVo.setField(field, newVal);
    }

    public final boolean hasElements() {
        return dataList.size() > 0;
    }

    private String parseData(Object value){
        if (value == null){
            return null;
        }

        return value.toString();
    }

    public final void addRow(@NotNull Column newRow) {
        dataList.add(newRow);
        super.fireTableDataChanged();
    }

    public final void addRow(int index,  @NotNull Column newRow) {
        dataList.add(index, newRow);
        super.fireTableDataChanged();
    }

    public final void addRow(@NotNull Collection<? extends Column> newRowList) {
        tempDataList = null;
        if (newRowList != null && !newRowList.isEmpty()){
            dataList.addAll(newRowList);
        }
        super.fireTableDataChanged();
    }

    public final void removeRow(int rowIndex) {
        dataList.remove(rowIndex);
        super.fireTableDataChanged();
    }

    public final void moveUpRow(int rowIndex) {
        if (rowIndex <= 0){
            return;
        }

        Column column = dataList.remove(rowIndex);
        dataList.add(rowIndex - 1, column);
        super.fireTableDataChanged();
    }

    public final void moveDownRow(int rowIndex) {
        if (rowIndex >= dataList.size() - 1){
            return;
        }

        Column column = dataList.remove(rowIndex);
        dataList.add(rowIndex + 1, column);
        super.fireTableDataChanged();
    }

    public final void rowCheck(int rowIndex) {
        Column columnNavigatable = dataList.get(rowIndex);
        //columnNavigatable.setChecked(!columnNavigatable.isChecked());
        super.fireTableDataChanged();
    }

    public final void clear() {
        dataList.clear();
        super.fireTableDataChanged();
    }

    public final void reset(@NotNull Collection<? extends Column> newRowList) {
        dataList.clear();
        tempDataList = null;
        if (newRowList != null && !newRowList.isEmpty()){
            dataList.addAll(newRowList);
        }
        super.fireTableDataChanged();
    }


    public final Column getRowData(int rowIndex) {
        if (rowIndex < -1 || rowIndex >= dataList.size()){
            return null;
        }
        return dataList.get(rowIndex);
    }

    public List<String> getColumnList() {
        return columnList;
    }

    /*public List<TableInfo> getCheckedRow(){
        return dataList.stream()
                .filter(tableInfo -> tableInfo.isChecked())
                .map(TableInfo::deepCopyWithCheckColumn)
                .collect(Collectors.toList());
    }*/




    public void filter(String tableName){
        if (tempDataList == null){
            tempDataList = new ArrayList<>(dataList);
        }


        if (tempDataList.size() == 0){
            return;
        }

        List<Column> list;
        if (StringUtils.isNotBlank(tableName)){
            list = tempDataList.stream()
                    .filter(tableInfo -> tableInfo.getName().contains(tableName))
                    .collect(Collectors.toList());
        } else {
            list = tempDataList;
        }

        dataList.clear();
        dataList.addAll(list);
        super.fireTableDataChanged();
    }

    public List<Column> getAllDataList() {
        if (tempDataList == null){
            return dataList;
        } else {
            return tempDataList;
        }
    }

    public DataChangedListener getDataChangedListener() {
        return dataChangedListener;
    }

    public void setDataChangedListener(DataChangedListener dataChangedListener) {
        this.dataChangedListener = dataChangedListener;
    }

    @FunctionalInterface
    public static interface DataChangedListener {
        public void dataChanged(int rowIndex, int columnIndex, Column column, String field, String newVal );
    }

}
